#include "scene.h"
#define BALA 1
#define LASER 2
#define PLASMA 3

std::map<std::string, coreMesh*> Scene::loaded_meshes;
std::map<std::string, int > Scene::loaded_textures;
std::vector<Instance*> Scene::instances_layer0;
std::vector<Instance*> Scene::instances_layer1;
std::vector<Instance*> Scene::instances_layer2;
std::vector<Projectile*> Scene::projectiles;
std::vector<pSystem*> pSystems;
Camera * Scene::camera = NULL;
Scene * Scene::scene;

void Scene::reloadScene(){
	scene = new Scene();
	instances_layer0.clear();
	instances_layer1.clear();
	instances_layer2.clear();
	
	pSystemManager::getPSManager()->pSystems_loaded.clear();
}	

Scene::Scene()
{
	//*********************
	//SHADERS
	Shader::init();
	
	//set the light properties
	light_position[0].set(-10,10,0);
	light_color[0].set(1,0,0); //white color

	light_position[1].set(20,20,0);
	light_color[1].set(0,0,1); //yellow color (OJO!! No, apenas tiene componente azul!!!)
	
	//Set variables
	ambient_factor.set(0,1,1);
	diffuse_factor.set(1,0,0);
	specular_factor.set(0,1,0);

	ambient_intensity = 0.3;
	diffuse_intensity = 0.7;
	specular_intensity = 1.0;

	glossiness = 20.0;
	
	pSystemManager::getPSManager();
	for( int i = 0; i < 200; i++){
		if(i>200) 
			projectiles.clear();
		projectiles.push_back(new Projectile());
	}
	lastProjectileEmpty = 0;
	last_time = getTime();
	estado_juego = EST_JUEGO;

	rtt = new RenderToTexture();
	rtt->init();
	rtt->create(256,256,true);
}

Scene::~Scene()
{
}

Scene * Scene::getScene(){
	//static Scene * scene = new Scene();
	if(scene == NULL) scene = new Scene();
	return scene;
}

void Scene::NewInstance(std::string _meshName, std::string _controllerName, Vector3 _pos, Matrix44 * _model, int _layer){
	
	Instance * i = new Instance(_meshName, _controllerName, _pos, _model);

	switch(_layer){
		case 0:
			instances_layer0.push_back(i);
			break;
		case 1:
			instances_layer1.push_back(i);
			break;
		case 2:
			instances_layer2.push_back(i);
			break;
		default:
			instances_layer0.push_back(i);
	}
}

void Scene::NewShip(std::string _meshName, std::string _controllerName, Vector3 _pos, Matrix44 * _model, std::string _tipo_nave, std::string _shader, std::string _team){
	
	Ship * i = new Ship(_meshName, _controllerName, _pos, _model, _tipo_nave, _shader, _team);
	instances_layer1.push_back(i);
}


coreMesh* Scene::LoadCore(std::string _name)
{
	std::map<std::string, coreMesh*>::iterator it;
	std::map<std::string, coreMesh*>::iterator it_end;

	it = loaded_meshes.find(_name);
	it_end = loaded_meshes.end();

	if(it == it_end){
		//crear
		coreMesh* m = new coreMesh();
		
		//char* file = (char*)malloc((strlen(_name)+8)*sizeof(char));
		std::string file;
		file = "ase/"+_name+".ase";
		//sprintf(file,"ase/%s.ase",_name);
		if (m->parseAse(file)){
			loaded_meshes[_name] = m;
		}
		else{
			return NULL;	
		}
		return m;
	}
	else{
		return it->second;
	}
}

bool Scene::LoadTextures(std::vector<std::string> _textures){

	long time_before = getTime();
	std::cout << "Uploading texturas" << std::endl;
	std::map<std::string, int>::iterator it;
	bool resp = true;
	for(int i = 0; i < _textures.size(); i++){
		std::cout << "* "<<_textures[i]<<"  loaded ..." << std::endl;
		it = loaded_textures.find(_textures[i]);
		if( it == loaded_textures.end() ){
			Textures * t = new Textures();
			if(!t->LoadTGA(_textures[i].data())) {
				std::cout << "Error loading texture " << _textures[i] << std::endl;
				std::cout << "Time elapsed: " << getTime() - time_before << "ms " << std::endl;
				resp = false;
			}
			//loaded_textures[_textures[i]] = t->texture_id;
			std::cout<<"Inserting texture on map .  id: "<< _textures[i] << " #:" << t->texture_id <<std::endl;
			loaded_textures.insert(std::pair<std::string,int>(_textures[i],t->texture_id));
			std::cout << " done" << std::endl;
			//t->~Textures();
		}
	}
	std::cout << "Time elapsed: " << getTime() - time_before << "ms " << std::endl;
	return resp;

}

bool Scene::ActivateTexture(std::string _name){
	std::map<std::string, int>::iterator it;
	//it = loaded_textures.begin();
	it = loaded_textures.find(_name);
	if( it != loaded_textures.end() ){
		int i = it->second;
		glEnable( GL_TEXTURE_2D );
		glBindTexture(GL_TEXTURE_2D, i);
		return true;
	}
	return false;
}

std::vector <Instance*>::iterator Scene::getInstanceIteratorBegin(int _layer){
	switch(_layer){
		case 0:
			return instances_layer0.begin();
			break;
		case 1:
			return instances_layer1.begin();
			break;
		case 2:
			return instances_layer2.begin();
			break;
		default:
			return instances_layer0.begin();
	}
}

std::vector <Instance*>::iterator Scene::getInstanceIteratorEnd(int _layer){
	switch(_layer){
		case 0:
			return instances_layer0.end();
			break;
		case 1:
			return instances_layer1.end();
			break;
		case 2:
			return instances_layer2.end();
			break;
		default:
			return instances_layer0.end();
	}
}

Ship* Scene::getShipById(int _id){
	std::vector<Instance*>::iterator it = instances_layer1.begin();
	
	for (it; it < instances_layer1.end(); it++){
		if((*it)->id_instance == _id) return (Ship*)(*it);
	}
	return NULL;
}

Ship* Scene::getShipPlayer(){
	for(int i = 0; i < instances_layer1.size(); i++){
		if(instances_layer1[i]->isPlayer) return (Ship*)instances_layer1[i];
	}
	return NULL;
}

Instance* Scene::getInstance(int _numInstance, int _layer){
	switch(_layer){
		case 0:
			if(_numInstance < instances_layer0.size()){		
				return instances_layer0[_numInstance];
			}
			std::cout << "ERROR Scene::getInstance( numInstance: "<< _numInstance << " , layer: " << _layer << " )" << std::endl;
			std::cout << "Instance requested ("<< _numInstance << ") is out of range (" << instances_layer0.size()-1 << ")" << std::endl;
			
			if(instances_layer0.size() >0 ){
				std::cout << "returning instance 0" << std::endl;
				return instances_layer0[0];
			}
			return NULL;
			break;
		case 1:
			if(_numInstance < instances_layer1.size()){		
				return instances_layer1[_numInstance];
			}
			std::cout << "ERROR Scene::getInstance( numInstance: "<< _numInstance << " , layer: " << _layer << " )" << std::endl;
			std::cout << "Instance requested ("<< _numInstance << ") is out of range (" << instances_layer1.size()-1 << ")" << std::endl;
			
			/*if(instances_layer1.size() > 0 ){
				std::cout << "returning instance 0" << std::endl;
				return instances_layer1[0];
			}*/

			return NULL;
			break;
		case 2:
			if(_numInstance < instances_layer2.size()){		
				return instances_layer2[_numInstance];
			}
			std::cout << "ERROR Scene::getInstance( numInstance: "<< _numInstance << " , layer: " << _layer << " )" << std::endl;
			std::cout << "Instance requested ("<< _numInstance << ") is out of range (" << instances_layer2.size()-1 << ")" << std::endl;
			
			if(instances_layer2.size() >0 ){
				std::cout << "returning instance 0" << std::endl;
				return instances_layer2[0];
			}
			return NULL;
			break;
		default:
			std::cout << "Layer " << _layer << " does not exists. Using default layer(0)"<<std::endl;
			if(_numInstance < instances_layer0.size()){		
				return instances_layer0[_numInstance];
			}
			std::cout << "ERROR Scene::getInstance( numInstance: "<< _numInstance << " , layer: " << _layer << " )" << std::endl;
			std::cout << "Instance requested ("<< _numInstance << ") is out of range (" << instances_layer0.size()-1 << ")" << std::endl;
			
			if(instances_layer0.size() >0 ){
				std::cout << "returning instance 0" << std::endl;
				return instances_layer0[0];
			}
			return NULL;
			break;
	}
}

int Scene::getInstanceSize(int _layer){
	switch(_layer){
		case 0:
			return instances_layer0.size();
			break;
		case 1:
			return instances_layer1.size();
			break;
		case 2:
			return instances_layer2.size();
			break;
		default:
			return instances_layer0.size();
	}
}

void Scene::addProjectile(Vector3 _origen, Vector3 _velocidad, int _owner, int _tipo){
		
	for(int i = 0; i < projectiles.size(); i++){
		if(!projectiles[i]->alive){
			lastProjectileEmpty = i;
			projectiles[i]->Set(_origen, _velocidad, _owner, _tipo);
			break;
		}
	}
}

void Scene::loadMatrices(const Matrix44& model, const Matrix44& view, const Matrix44& projection)
{
	//We upload the matrices into opengl
	glMatrixMode( GL_MODELVIEW );
	Matrix44 modelview;
	modelview = model * view;
	glLoadMatrixf( modelview.m );

	glMatrixMode( GL_PROJECTION );
	glLoadMatrixf( projection.m );

	glMatrixMode( GL_MODELVIEW );
}

void Scene::setCamera(){
	if (!camera){
		camera = new Camera();
	}
	camera->lookAt( Vector3(0,25,50),Vector3(0,0,0), Vector3(0,1,0));
	camera->setPerspective(75,WINDOW_WIDTH/(float)WINDOW_HEIGHT,0.01,10000);
}

Camera * Scene::getCamera(){
	return this->camera;
}


void Scene::renderScene(){
	Shader * shader;
	Ship * ship;
	Camera cam2D;
	Matrix44 * model;
	std::string CoreID;
	std::vector <Instance*>::iterator it;
	pSystemManager * psManager;

	
	glDisable(GL_CULL_FACE);
	model = new Matrix44();
	model->setIdentity();
	//We load the MODELVIEW into opengl
	Scene::loadMatrices(*model, camera->view_matrix, camera->projection_matrix);
	
	this->camera->set();
	
	//Layer 1: Cubemap
	Scene::renderSceneLayer(0);

	//Layer 2: Ships
	this->rtt->bind();
		Scene::renderSceneLayer(1);
	this->rtt->unbind();
	
	//Layer 3: Environment
	Scene::renderSceneLayer(2);

	//Render Particle Systems
	psManager = pSystemManager::getPSManager();
	psManager->render();
	for (int i = 0; i < projectiles.size(); i++)
	{
		if(projectiles[i]->alive) projectiles[i]->render();
	}
	
	DrawHUD();
	
	if(estado_juego != EST_JUEGO){
		glPushAttrib(GL_ALL_ATTRIB_BITS);
		glEnable(GL_BLEND);                                                     
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_CULL_FACE);
		glDepthMask(false);
		Camera cam2d;
		cam2d.setOrthographic(-1,1,1,-1,0,1);
		cam2d.set();
	}
	if(estado_juego == EST_GANA){
		DrawQuad(2,2,0,0,0,"winner");
	} else if (estado_juego == EST_PIERDE){
		DrawQuad(2,2,0,0,0,"loser");
		model = new Matrix44();
		model->setIdentity();
		ship = new Ship("x3_runner","",Vector3(0,0,0),model,"x3_runner","shader","red");
		ship->speed = 1;
	}
	if(estado_juego != EST_JUEGO){
		glPopAttrib();
	}

	//Check for errors on OpenGL
	GLenum errCode ;
	const GLubyte *errString;
	if ((errCode = glGetError()) != GL_NO_ERROR) {
		errString = gluErrorString(errCode);
		fprintf (stderr, "OpenGL Error: %s\n", errString);
	}
	//POSTPROCESSING
	//Rendertotexture
	glEnable( GL_TEXTURE_2D );
	this->rtt->bindTexture();

	//cam2D.setOrthographic(0,WINDOW_WIDTH,0,WINDOW_HEIGHT,-1,+1);
	//cam2D.set();

	//Shader * shader;
	//shader = new Shader();
	//shader = Shader::Load("frost.vs","frost.vs");
	//glEnable(GL_BLEND);                                                     
	//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_COLOR);
	//glDepthMask(false);

	glBegin(GL_QUADS);
	glColor4f(1.0,1.0,1.0,0.5);
	glTexCoord2f(0,1);
	glVertex3f(0,0,0);
	glTexCoord2f(1,1);
	glVertex3f(200,0,0);
	glTexCoord2f(1,0);
	glVertex3f(200,200,0);
	glTexCoord2f(0,0);
	glVertex3f(0,200,0);
	glEnd();

}

void Scene::renderSceneLayer(int _layer){
	Matrix44 * matrix;
	Matrix44 * model;
	std::string CoreID;
	Clipper * clipper;
	Shader *  shader;
	Ship * ship;
	std::vector <Instance*>::iterator it, itf;

	matrix = new Matrix44();
	matrix->setIdentity();
	clipper = new Clipper();

	//We load the MODELVIEW into opengl
	Scene::loadMatrices(*matrix, camera->view_matrix, camera->projection_matrix);

	if (_layer == 0) glDisable(GL_DEPTH_TEST);
	else glEnable(GL_DEPTH_TEST);

	glColor3f(1,1,1);
	it = Scene::getInstanceIteratorBegin(_layer);
	itf = getInstanceIteratorEnd(_layer);

	for(it; it != itf; ++it){
		
		coreMesh* mesh;
		glPushMatrix();
		ship = (Ship*)(*it);
		CoreID = ship->id_mesh;
		loadMatrices(*ship->model,camera->view_matrix,camera->projection_matrix);
		glColor4f(1.0,1.0,1.0,1.0);
		
		shader = ship->shader;
		mesh = LoadCore(CoreID);

		if (!mesh->multiTexture)
			if(!ActivateTexture(CoreID))
				std::cout<<"Error Loading texture \""<<CoreID<<"\""<<std::endl;
		
		if ( shader != NULL){
			UploadVariablesShader(shader,mesh,ship);
		}
		clipper->ExtractFrustum();
		if(clipper->SphereInFrustum(mesh->media.x,mesh->media.y,mesh->media.z,(mesh->media - mesh->lejano).length()))
			mesh->render();

		glPopMatrix();
		glDisable( GL_TEXTURE_2D );
		if ((*it)->timerRebote > 0){
			Vector3 ori = (*it)->model->getPosition();
			Vector3 fin_ver = (*it)->rebote * 20;
			glColor3f(1,0,0);
			glBegin(GL_LINES);
				glVertex3f(ori.x,ori.y,ori.z);
				glVertex3f(fin_ver.x+ori.x,fin_ver.y+ori.y,fin_ver.z+ori.z);
			glEnd();
		}
		if (shader != NULL)  shader->disable();
		glEnable(GL_DEPTH_TEST);
	}

}

void Scene::updateScene( double seconds_elapsed){

	if(estado_juego != EST_JUEGO) return;

	std::vector <Projectile*>::iterator itP;
	std::vector <Instance*>::iterator itI;
	std::vector <Instance*>::iterator itI2;
	std::vector <pSystem*>::iterator itPs;
	SoundManager * SM;
	pSystemManager * psManager = pSystemManager::getPSManager();
	itP = projectiles.begin();
	std::vector<int> naveseliminar;
	
	std::map<std::string,int> equipos;
	std::map<std::string,int>::iterator itE;
	std::string team;
	Ship * shipE;
	Ship * player = getShipPlayer();
	//cuento equipos y naves enemigas
	for(int i = 0; i < instances_layer1.size(); i++){
		shipE = (Ship*)instances_layer1[i];
		team = shipE->getTag("team");
		if(team != "")	equipos[team]++;
	}
	std::string playerTeam = player->getTag("team");
	itE = equipos.find(playerTeam);

	if(itE != equipos.end() && equipos.size()==1) estado_juego = EST_GANA;
	else if(itE == equipos.end()) estado_juego = EST_PIERDE;

	//DE ACA SACAMOS CONDICION DE VICTORIA/DERROTA
	
	for(itP; itP < projectiles.end(); itP++){
		(*itP)->recalc();
	}

	//colisiones
	itI = getInstanceIteratorBegin(1);
	int j = 0;
	bool isColided;
	Vector3 pos, posicion_proj, direccion_proj,collision;
	std::string CoreID,msg;
	Ship * ship;
	Ship * ship2;
	Ship * sh;
	//BASS_3DVECTOR  bpos,  bvel,  bfront,  btop;
	for(itI; itI != getInstanceIteratorEnd(1); itI++){
		ship = (Ship*)(*itI);
		pos = ship->model->getPosition();
		if(ship->isPlayer){
			/*
			bpos.x = pos.x;
			bpos.y = pos.y;
			bpos.z = pos.z;
			
			bvel.x = ship->velocidad.x;
			bvel.y = ship->velocidad.y;
			bvel.z = ship->velocidad.z;

			Vector3 front = ship->model->frontVector();
			bfront.x = front.x;
			bfront.y = front.y;
			bfront.z = -front.z;

			Vector3 sTop = ship->model->topVector();
			btop.x = sTop.x;
			btop.y = sTop.y;
			btop.z = sTop.z;
			bool bass = BASS_Set3DPosition(&bpos,&bvel,&bfront,&btop);
			BASS_Apply3D();
			*/
		}
		if((getTime() - ship->timerRebote) > 250){
			ship->timerRebote = 0;
			ship->rebote.set(0,0,0);
		}
		if ( ship->timerRebote > 0) ship->Move("rebote",1,seconds_elapsed);
		if(!ship->alive ){//&& !ship->isPlayer){
			//nave muerta, creamos explosion..
			//sonido explosion
			//Sample * sample = &SM->getSampleID("ship_explossion");
			//SM->setSamplerChannel("ship_explossion", BASS_SampleGetChannel(sample->sample, false));
			//bool bass = BASS_ChannelSet3DAttributes(sample->channel,BASS_3DMODE_NORMAL,20,500.0,360,360,1);
			//bass = BASS_ChannelSet3DPosition(sample->channel,&bpos,&bfront,&bvel);
			//BASS_Apply3D();
			
			double dist = getDistance(pos,getShipPlayer()->model->getPosition());
			if(dist < 500.0)
				SM->playSound("ship_explossion",1);
	

			//particulas explosion
			pos = *ship->model * Vector3(0,0,0);
			shipExplossionPS * p = new shipExplossionPS();
			p->create(pos,40);
			psManager->addPSystem(p);
			ringExplossionPS * rp = new ringExplossionPS();
			rp->create(pos,100);
			psManager->addPSystem(rp);
			
			naveseliminar.push_back(j);
			if(ship->isPlayer){
				estado_juego = EST_PIERDE;
				return;

			}
			//eliminar nave
		}
		else{
			itP = projectiles.begin();
			CoreID = (*itI)->id_mesh;
			coreMesh * m = loaded_meshes[CoreID];
			m->colmodel->setTransform((*itI)->model->m);
			for(itP; itP != projectiles.end();itP++){
				if(!(*itP)->alive || ((*itP)->owner == (*itI)->id_instance)) continue;
				posicion_proj = (*itP)->origen + ( (*itP)->velocidad*(getTime()- (*itP)->birth));
				direccion_proj = (*itP)->velocidad;
				//ahora las los projectiles son rectangulos...
				isColided = false;
				isColided = m->colmodel->sphereCollision(posicion_proj.v,(float)(*itP)->size.length()/2);
				if(isColided){
					collision;
					m->colmodel->getCollisionPoint(collision.v,false);
					sh = (Ship*)(*itI);
					char n[10];
					sprintf(n,"%d",(*itP)->damage);
					msg = "hurt|";
					msg += n;
					sh->processMessage(msg);
 					explossionPS * p = new explossionPS();
					p->create(collision,10);
					psManager->addPSystem(p);
					(*itP)->alive = false;
				}
			}
			itI2 = instances_layer1.begin();
			isColided = false;
			coreMesh * m2;
			Vector3 pos;
			float radio;
			for(itI2;itI2 != instances_layer1.end(); itI2++){
				ship2 = (Ship*)(*itI2);
				if(ship->id_instance == ship2->id_instance) continue;
				m2 = loaded_meshes[ship2->id_mesh];
				m2->colmodel->setTransform(ship2->model->m);
				if((*itI)->id_mesh == (*itI2)->id_mesh){
					m->colmodel->collision(m2->colmodel,-1,0,ship2->model->m);
				} else {
					isColided = m->colmodel->collision(m2->colmodel);
				}
				if(isColided){
					itI2 = instances_layer1.end();
					ship->rebote = -(ship->model->frontVector() + ship2->model->frontVector());
					ship->timerRebote = getTime();
					break;
				}
			}

		}
		j++;
	}
	for(int i = naveseliminar.size(); i > 0 ; i--){
		int j = naveseliminar[i-1];
		ship = (Ship*)instances_layer1.at(j);
		instances_layer1.erase(instances_layer1.begin()+j); 
		ship->~Ship();
	}
	itI = instances_layer1.begin();
	for (itI; itI < instances_layer1.end();itI++){
		(*itI)->model->orthonormalize();
		//(*itI)->model->setFrontAndOrthonormalize

		if((*itI)->controller != NULL)
			(*itI)->controller->recalc((Ship*)(*itI),seconds_elapsed);
		
	}
	psManager->recalc();
	getShipPlayer()->processMessage("regenerate|shield");
}

void Scene::UploadVariablesShader(Shader * _shader, coreMesh * _mesh, Ship* _ship)
{
	Matrix44 _model = *_ship->model;
	Camera * camera = Scene::getCamera();
	_shader->enable();

	Vector3 light_position[2];
	Vector3 light_color[2];
	//Colores;
	Vector3 ambient_factor;
	Vector3 diffuse_factor;
	Vector3 specular_factor;

	//Intensidades
	float ambient_intensity;
	float diffuse_intensity;
	float specular_intensity;

	//Alpha
	float glossiness;

	light_position[0].set(-10,20,0);
	light_color[0].set(0,0,1); //white color

	light_position[1].set(10,15,0);
	light_color[1].set(0,0,1); //yellow color (OJO!! No, apenas tiene componente azul!!!)
	
	//Set variables
	ambient_factor.set(0,1,1);
	diffuse_factor.set(1,0,0);
	specular_factor.set(0,1,0);

	ambient_intensity = 0.3;
	diffuse_intensity = 0.7;
	specular_intensity = 1.0;

	glossiness = 20.0;


	//the regular model of the object
	if (_shader->IsVar("model"))
		_shader->setMatrix44("model", _model.m );

	//to rotate the normals we need the model without the translation
	if (_shader->IsVar("modelt"))
		_shader->setMatrix44("modelt", _model.getRotationMatrix()->m );

	if(_shader->IsVar("camera_pos"))
		_shader->setVector3("camera_pos", camera->eye);

	if(_shader->IsVar("texture"))
		_shader->setTexture("texture",loaded_textures[_mesh->texturesID[0]]);

	if (_shader->IsVar("light_color"))
	{
		_shader->setVector3("light_color", light_color[0]);
		_shader->setVector3("light_position", light_position[0]);
	}

	if (_shader->IsVar("light_color[0]"))
	{
		_shader->setVector3("light_color[0]", light_color[0]);
		_shader->setVector3("light_position[0]", light_position[0]);
	}

	if (_shader->IsVar("light_color[1]"))
	{
		_shader->setVector3("light_color[1]", light_color[1]);
		_shader->setVector3("light_position[1]", light_position[1]);
	}
	
	//the camera position
	if (_shader->IsVar("camera_eye"))
		_shader->setVector3("camera_eye", camera->eye);

	//Colores
	if (_shader->IsVar("ambient_factor"))
		_shader->setVector3("ambient_factor", ambient_factor);
	if (_shader->IsVar("diffuse_factor"))
		_shader->setVector3("diffuse_factor", diffuse_factor);
	if (_shader->IsVar("specular_factor"))
		_shader->setVector3("specular_factor", specular_factor);

	if (_shader->IsVar("ambient_intensity"))
		_shader->setFloat("ambient_intensity", ambient_intensity);
	if (_shader->IsVar("diffuse_intensity"))
		_shader->setFloat("diffuse_intensity", diffuse_intensity);
	if (_shader->IsVar("specular_intensity"))
		_shader->setFloat("specular_intensity", specular_intensity);

	if (_shader->IsVar("glossiness"))
		_shader->setFloat("glossiness", glossiness);

	//the model view projection
	if (_shader->IsVar("mvp")) //check if the shader needs this var
		_shader->setMatrix44("mvp", ((_model) * camera->view_matrix * camera->projection_matrix).m ); //upload the mvp to the shader

	//the regular model of the object
	if (_shader->IsVar("model"))
		_shader->setMatrix44("model", _model.m );

	//to rotate the normals we need the model without the translation
	if (_shader->IsVar("normal_model"))
		_shader->setMatrix44("normal_model", _model.getRotationMatrix()->m );

	if (_shader->IsVar("modelt"))
		_shader->setMatrix44("modelt", _model.getRotationMatrix()->m );

	if (_shader->IsVar("emitterLight"))
		_shader->setVector3("emitterLight", _ship->shipColor);
}

void Scene::DrawHUD()
{
	Camera cam2D;
	Camera cam3D = *Scene::getCamera();
	//obtenemos la posicion de todas las naves

	std::vector<Instance*>::iterator it = getInstanceIteratorBegin(1);
	std::vector<Instance*>::iterator itf = getInstanceIteratorEnd(1);

	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glEnable(GL_BLEND);                                                     
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);      
    glDisable(GL_TEXTURE_2D);
	glDisable(GL_CULL_FACE);
	glDepthMask(false);


	//INFO NAVES
	Vector3 topcamera = camera->getLocalVector(Vector3(0,1,0));
    Vector3 rightcamera = camera->getLocalVector(Vector3(1,0,0));
    Vector3 rightPTop = rightcamera + topcamera;
    Vector3 rightMTop = rightcamera - topcamera;

    rightPTop.normalize();
    rightMTop.normalize();

	it = getInstanceIteratorBegin(1);
	itf = getInstanceIteratorEnd(1);

	float shield, life,lratio,sratio ;
	int i = 1;
	bool isAhead = false;
	Vector3 p1,p2,p3,width,pos,center;
	Vector3 radio;
	coreMesh * mesh;
	Matrix44 *model;
	std::vector<double> sizes;
	std::vector<Vector3> points;
	std::vector<Vector3> lifes;
	std::vector<Vector3> shields;
	std::vector<Ship*> Ships;
	std::vector<Vector3> shipPositions;
	double size;
	Ship * player = getShipPlayer();
	cam2D.setOrthographic(0,WINDOW_WIDTH,0,WINDOW_HEIGHT,-1,cam3D.far_plane);
	cam3D.set();

	for (it; it != itf; it++){
		Ship * ship = (Ship*)(*it);
		life = ship->life;
		shield = ship->shield;
		sratio = (shield/ship->shield_max);
		lratio = (life/ship->life_max);
		mesh = LoadCore((*it)->id_mesh);
		model = (*it)->model;
		pos = model->getPosition();
		shipPositions.push_back(pos);
		radio = (mesh->lejano - mesh->media);
		isAhead = Scene::camera->isAhead(pos);
		if(isAhead && !ship->isPlayer){
			center = get2DPoint(pos);
			center = center + cam3D.offset;
			size = radio.length()/2;
			if (size > 150) size = 150;
			bool atBorder = false;
			if(center.x < 0 || (!isAhead && center.x < WINDOW_WIDTH/2)){
				center.x = 5;
				atBorder = true;
			} else if(center.x > WINDOW_WIDTH || (!isAhead && center.x >= WINDOW_WIDTH/2)){
				center.x = WINDOW_WIDTH - 5;
				atBorder = true;
			}
			if(center.y < 0 || (!isAhead && center.y < WINDOW_HEIGHT/2)){
				center.y = 5;
				atBorder = true;
			} else if(center.y > WINDOW_HEIGHT || (!isAhead && center.y >= WINDOW_HEIGHT/2)){
				center.y = WINDOW_HEIGHT - 5;
				atBorder = true;
			}
			if(atBorder==true){
				size = 10;
			}
			
			//dibujar vida de otras naves
			points.push_back(center);
			lifes.push_back(Vector3(center.z,center.z*lratio,lratio));
			shields.push_back(Vector3(center.z+6,center.z*sratio,sratio));
			sizes.push_back(size);
			
		}
		if(!ship->isPlayer)
			Ships.push_back(ship);

		i++;
	}
	cam2D.set();
	glColor4f(0.1,0.8,0.2,1.0);
	double hsx, hsy;
	glEnable(GL_TEXTURE_2D);
	ActivateTexture("hud-target");
	glBegin(GL_QUADS);
	std::string teamPlayer = getShipPlayer()->getTag("team");
	StringUtils::MakeLower(teamPlayer);
	StringUtils::TrimLeft(teamPlayer);
	StringUtils::TrimRight(teamPlayer);
	std::string teamShip;
	std::string otherTeam, playerTeam;
	for (int i = 0; i < points.size(); i++){
		//recuadro
		teamShip = Ships[i]->getTag("team");
		StringUtils::MakeLower(teamShip);
		//StringUtils::TrimLeft(teamShip);
		//StringUtils::TrimRight(teamShip);
		hsx = sizes[i];
		hsy = sizes[i];
		glColor3f(1,1,1);
		if(teamShip != ""){
			if(teamShip == teamPlayer) glColor4f(0.2,0.8,0.2,0.7);
			else glColor4f(0.8,0.2,0.2,0.7);
		}else{
			glColor4f(0.3,0.3,0.3,0.5);
		}
		/*
		if(teamShip == teamPlayer){
			glColor4f(0.2,0.8,0.2,0.7);
		}else if (teamShip != teamPlayer && teamShip != ""){
			glColor4f(0.8,0.2,0.2,0.7);
		}else {
			glColor4f(0.3,0.3,0.3,0.5);
		}
		*/
		glTexCoord2f(0.0,1.0); glVertex3f(+points[i].x - hsx,+points[i].y + hsy, points[i].z);
		glTexCoord2f(1.0,1.0); glVertex3f(+points[i].x + hsx,+points[i].y + hsy, points[i].z);
		glTexCoord2f(1.0,0.0); glVertex3f(+points[i].x + hsx,+points[i].y - hsy, points[i].z);
		glTexCoord2f(0.0,0.0); glVertex3f(+points[i].x - hsx,+points[i].y - hsy, points[i].z);
	}
	glEnd();
	glDisable(GL_TEXTURE_2D);
	glBegin(GL_QUADS);
	for (int i = 0; i < lifes.size(); i++){
		//VIDA
		lifes[i].x += 3;
		hsx = lifes[i].y;
		hsy = 3;
		glColor4f(1.0,lifes[i].z,lifes[i].z,0.6);	
		glTexCoord2f(0.0,1.0); glVertex3f(+points[i].x - hsx,-lifes[i].x+points[i].y + hsy, points[i].z);
		glTexCoord2f(1.0,1.0); glVertex3f(+points[i].x + hsx,-lifes[i].x+points[i].y + hsy, points[i].z);
		glTexCoord2f(1.0,0.0); glVertex3f(+points[i].x + hsx,-lifes[i].x+points[i].y - hsy, points[i].z);
		glTexCoord2f(0.0,0.0); glVertex3f(+points[i].x - hsx,-lifes[i].x+points[i].y - hsy, points[i].z);
		shields[i].x +=3;
		hsx = shields[i].y;
		hsy = 3;
		//ESCUDO
		glColor4f(0.0,0.0,1-shields[i].x,0.6);	
		glTexCoord2f(0.0,1.0); glVertex3f(+points[i].x - hsx,-shields[i].x+points[i].y + hsy, points[i].z);
		glTexCoord2f(1.0,1.0); glVertex3f(+points[i].x + hsx,-shields[i].x+points[i].y + hsy, points[i].z);
		glTexCoord2f(1.0,0.0); glVertex3f(+points[i].x + hsx,-shields[i].x+points[i].y - hsy, points[i].z);
		glTexCoord2f(0.0,0.0); glVertex3f(+points[i].x - hsx,-shields[i].x+points[i].y - hsy, points[i].z);
	}
	glEnd();

	glColor4f(0.9,0.2,0.2,1.0);
	DrawQuad(30, 30, WINDOW_WIDTH/2, (WINDOW_HEIGHT/2) - 100, 0, "cruz");
	//Dibujar vida, escudo y demas del jugador

	life = player->life / player->life_max;
	shield = player->shield / player->shield_max;
	double box_width = WINDOW_WIDTH/4;
	double box_height = WINDOW_HEIGHT/20;
	
	//vida
	glColor4f(0.5,0.9,0.2,0.7);
	DrawQuad(box_width*life, box_height, WINDOW_WIDTH-box_width/2, WINDOW_HEIGHT-(3*box_height/2), 0, "");
	//escudo
	glColor4f(0.2,0.3,0.9,0.7);
	DrawQuad(box_width*shield, box_height, WINDOW_WIDTH-box_width/2, WINDOW_HEIGHT-(box_height/2), 0, "");

	//naves vivas de otros equipos;
	
	std::map<std::string,int> equipos;
	std::map<std::string,int>::iterator itE;
	std::string team;
	Ship * shipE;
	//cuento equipos y naves enemigas
	for(int i = 0; i < instances_layer1.size(); i++){
		shipE = (Ship*)instances_layer1[i];
		team = shipE->getTag("team");
		equipos[team]++;
	}
	//dibujamos naves
	itE = equipos.begin();
	playerTeam = player->getTag("team");
	int j = 1;
	double hs = 30;
	for(itE; itE != equipos.end(); ++itE){
		if(itE->first != "" ){//&& itE->first != playerTeam){
			if(itE->first == "red") glColor4f(1.0,0.0,0.0,0.7);
			if(itE->first == "green") glColor4f(0.0,1.0,0.0,0.7);
			if(itE->first == "blue") glColor4f(0.0,0.0,1.0,0.7);
			for(int i = 0; i < itE->second; i++){
				DrawQuad(hs,hs,WINDOW_WIDTH-((2*(i+1) + 1)/2)*hs,((2*j + 1)/2)*hs,0,"ship-icon");
			}
		j++;
		}
		
	}

	//=======================================================
	//========================RADAR==========================
	//=======================================================
	//cam3D.setOrthographic(0,100,100,0,10,0,10);
	double W_HEIGHT, W_WIDTH;
	W_HEIGHT = WINDOW_HEIGHT/4;
	W_WIDTH = WINDOW_WIDTH/6;
	glViewport(0,0,W_WIDTH,W_HEIGHT);
	
	Vector3 eye = Vector3(0,-0.22,0.6);//*player->model * Vector3(0,300,200);
	Vector3 playerPos = player->model->getPosition();
	Vector3 front = player->model->frontVector();
	cam3D.lookAt( eye, Vector3(0,0,0), Vector3(0,1,0));
	cam3D.set();

	Vector3 distMax, norm;
	distMax.set(0,0,0);
	float fdistMax = 0;
	float distAux;
	for (int i = 0; i < shipPositions.size(); i++){
		distAux = getDistance(playerPos,shipPositions[i]);
		if(fdistMax < distAux){
			distMax = shipPositions[i];
			fdistMax = distAux;
		}
	}
	//normalizamos con distMax
	
	Vector3 posR;

	glColor4f(0.7,0.7,0.7,0.3);
	glBegin(GL_QUADS);
	//Fondo
	hsx = W_WIDTH/2;
	hsy = W_HEIGHT/2;
	posR.set(0,0,0);
	glTexCoord2f(0.0,1.0); glVertex3f(posR.x - hsx,posR.y + hsy, posR.z);
	glTexCoord2f(1.0,1.0); glVertex3f(posR.x + hsx,posR.y + hsy, posR.z);
	glTexCoord2f(1.0,0.0); glVertex3f(posR.x + hsx,posR.y - hsy, posR.z);
	glTexCoord2f(0.0,0.0); glVertex3f(posR.x - hsx,posR.y - hsy, posR.z);

	//Plano
	glColor4f(1.0,1.0,1.0,0.5);
	posR.set(0,0,0);
	hsx = 0.5;
	hsy = 0.5;
	glTexCoord2f(0.0,1.0); glVertex3f(posR.x - hsx,posR.y + hsy, posR.z);
	glTexCoord2f(1.0,1.0); glVertex3f(posR.x + hsx,posR.y + hsy, posR.z);
	glTexCoord2f(1.0,0.0); glVertex3f(posR.x + hsx,posR.y - hsy, posR.z);
	glTexCoord2f(0.0,0.0); glVertex3f(posR.x - hsx,posR.y - hsy, posR.z);
	glEnd();

	glPointSize(5);
	glColor4f(1.0,0.0,0.0,0.5);
	
	Vector3 aux,dir, otherPos;
	double alfa = 0;
	float modulo = 0;
	
	playerTeam = player->getTag("team");
	glBegin(GL_POINTS);
	for (int i = 0; i < Ships.size(); i++){
		otherTeam = Ships[i]->getTag("team");
		otherPos = Ships[i]->model->getPosition();
		dir = otherPos - playerPos;
		dir.normalize();
		modulo = getDistance(playerPos, otherPos);
		modulo /= fdistMax;
		modulo *= 0.5;
		dir = dir * modulo;
		dir = -dir;
		alfa = -0.15;
		if(dir.z >= 0) alfa = 0.15;
		if(otherTeam != ""){
			if(otherTeam != playerTeam){
				glColor4f(1.0,0.0,0.0,(0.7)+alfa);
			}
			else{
				glColor4f(0.0,1.0,0.0,(0.6)+alfa);
			}
		}
		else{
			glColor4f(0.3,0.3,0.3,(0.5)+alfa);
		}
		
		glVertex3fv(dir.v);
	
	}
	glColor3f(1.0,1.0,1.0);
	glVertex3f(0.0,0.0,0.0);
	glEnd();

	glColor3f(1.0,1.0,1.0);
	front.normalize();
	front = front * 0.3 ; 
	glBegin(GL_LINES);
		glVertex3f(0.0,0.0,0.0);
		glVertex3fv(front.v);
	glEnd();


	glPopAttrib();
	glViewport(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
	Scene::camera->set();
	
	i = glGetError();
	assert(i == GL_NO_ERROR);
}

void Scene::DrawQuad(float _sizex , float _sizey, float _pos_x, float _pos_y, float _pos_z, std::string _texture){
	
	float hsx = (_sizex)/2.0;
	float hsy = (_sizey)/2.0;
	//glDisable(GL_TEXTURE_2D);

	if(_texture != ""){
		glEnable(GL_TEXTURE_2D);
		ActivateTexture(_texture);
	}

	glBegin(GL_QUADS);
	glTexCoord2f(0.0,1.0); glVertex3f(+_pos_x - hsx,+_pos_y + hsy, _pos_z);
	glTexCoord2f(1.0,1.0); glVertex3f(+_pos_x + hsx,+_pos_y + hsy, _pos_z);
	glTexCoord2f(1.0,0.0); glVertex3f(+_pos_x + hsx,+_pos_y - hsy, _pos_z);
	glTexCoord2f(0.0,0.0); glVertex3f(+_pos_x - hsx,+_pos_y - hsy, _pos_z);

	glEnd();

	if(true || _texture != ""){
		glDisable(GL_TEXTURE_2D);
	}

}

void Scene::DrawQuad2D(float _sizex , float _sizey, float _pos_x, float _pos_y){
	
	float hsx = (_sizex)/2.0;
	float hsy = (_sizey)/2.0;

	glBegin(GL_QUADS);
	glTexCoord2f(0.0,1.0); glVertex2f(+_pos_x - hsx,+_pos_y + hsy);
	glTexCoord2f(1.0,1.0); glVertex2f(+_pos_x + hsx,+_pos_y + hsy);
	glTexCoord2f(1.0,0.0); glVertex2f(+_pos_x + hsx,+_pos_y - hsy);
	glTexCoord2f(0.0,0.0); glVertex2f(+_pos_x - hsx,+_pos_y - hsy);
	glEnd();

	glDisable(GL_TEXTURE_2D);
}

Vector3 Scene::get2DPoint(Vector3 & worldPoint)
{
	double modelMatrix[16];
	double projMatrix[16];
	int viewport[4];
	glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
	glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
	glGetIntegerv(GL_VIEWPORT, viewport);
	double x, y, z;
	bool result = gluProject(worldPoint.x, worldPoint.y, worldPoint.z, modelMatrix, projMatrix, viewport, &x, &y, &z);
	return Vector3(x,viewport[3]-y,z);
	
}